package com.labofjet.system.aop;

import com.labofjet.common.aop.AspectOrder;
import com.labofjet.common.dto.ContextDto;
import com.labofjet.common.util.CommonUtils;
import com.labofjet.system.conf.WhiteListProperties;
import com.labofjet.system.dto.SysPermissionDto;
import com.labofjet.system.dto.SysUserDto;
import com.labofjet.system.enums.EPermissionType;
import com.labofjet.system.enums.EState;
import com.labofjet.system.util.SysCommonUtils;
import org.apache.commons.collections.CollectionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 权限过滤
 */
@Aspect
@Component
@Order(AspectOrder.URLPERMISSION_ORDER)
public class URLPermissionAspect {

	@Autowired
	private WhiteListProperties whiteListProperties;

	@Around(value = "within(@org.springframework.web.bind.annotation.RestController *)")
	public Object controllerLog(ProceedingJoinPoint pjp) throws Throwable {
		// 白名单
		String requestUri = CommonUtils.getCurrentRequest().getRequestURI();
		String requestUrl = CommonUtils.getCurrentRequest().getRequestURL().toString();
		if (this.contain(whiteListProperties.getUrlList(), requestUri)) { // 白名单放行
			return pjp.proceed();
		}

		// 权限校验
		ContextDto contextDto = new ContextDto();
		contextDto.setSuccess(false);

		Method method = ((MethodSignature) pjp.getSignature()).getMethod();
		Class<?> classClass = pjp.getTarget().getClass();
		RestController restController = classClass.getAnnotation(RestController.class);
		String controllerMappings = "";
		if (restController != null) { // controller 映射1个地址
			controllerMappings = restController.value();
		}
		RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
		if (requestMapping == null) { // 不是映射方法直接放行
			return pjp.proceed();
		}
		List<String> wholeMappings = new ArrayList<>(Arrays.asList(requestMapping.value()));
		for (int i = 0; i < wholeMappings.size(); i++) { // 计算完整映射地址
			String methodMappingString = wholeMappings.get(i);
			wholeMappings.set(i, controllerMappings + methodMappingString);
		}
		SysUserDto user = SysCommonUtils.getCurrentUser();
		if (user == null) { // 未登录
			contextDto.setMessage("用户未登录,无权请求该URL:" + requestUrl);
			return contextDto;
		} else {
			if (CollectionUtils.isEmpty(user.getSysRoleIdList())) {
				contextDto.setMessage("用户权限为空,不能请求URL:" + requestUrl);
				return contextDto;
			}
			if (user.getSysRoleIdList().contains(1)) { // admin
				return pjp.proceed();
			}
			// 用户权限列表为空
			List<SysPermissionDto> permissions = user.getSysPermissionDtos();
			if (CollectionUtils.isEmpty(permissions)) {
				contextDto.setMessage("没有权限请求该URL:" + requestUrl);
				return contextDto;
			}
			boolean hasPermission = false;
			for (SysPermissionDto permission : permissions) {
				if (EPermissionType.URL.getCode().equals(permission.getType()) && EState.VALID.getCode().equals(permission.getState())) {
					if (controllerMappings.equals(permission.getSn())) {
						hasPermission = true;
						break;
					} else if (this.contain(wholeMappings, permission.getSn())) {
						hasPermission = true;
						break;
					}
				}
			}
			if (!hasPermission) {
				contextDto.setMessage("没有权限请求该URL:" + requestUrl);
				return contextDto;
			}
		}

		return pjp.proceed();
	}

	private boolean contain(List<String> arr, String s) {
		if (CollectionUtils.isEmpty(arr)) {
			return false;
		}
		for (String s1 : arr) {
			if (s1.equals(s)) { // 完全匹配
				return true;
			} else if (s1.contains(s) && s1.substring(s.length(), s1.length()).startsWith("/")) { // s=/menu/a s1=/menu
				return true;
			}
		}
		return false;
	}
}
